<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Route snapper demo</title>
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
    <link
      href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css"
      rel="stylesheet"
    />
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
      #snap-tool {
        position: absolute;
        top: 10px;
        right: 10px;
        padding: 10px;

        background-color: white;
      }
      #top-left {
        position: absolute;
        z-index: 5;
        padding: 20px;
        background-color: white;
        max-width: 400px;
      }
      .row {
        margin: 16px 0px;
      }
      #status {
        border: 4px solid;
        padding: 6px;
      }
    </style>
  </head>
  <body>
    <div id="top-left">
      <div class="row">
        <a href="import.html">Create your own graph files</a>
      </div>
      <div class="row">
        <label
          >Change graph file:
          <input type="file" id="fileInput" />
        </label>
      </div>
      <div class="row">
        <button type="button" id="clear">Clear routes</button>
      </div>
      <div class="row">
        <button type="button" id="start">
          Start (not part of the main control)
        </button>
      </div>
      <div class="row">
        <button type="button" id="stop">
          Stop (not part of the main control)
        </button>
      </div>
      <div class="row">
        <button type="button" id="debugGraph">
          Download debug graph as GeoJSON
        </button>
      </div>
      <div class="row">Click an existing route to edit</div>
      <div id="status">Inactive</div>
      <div class="row">
        <button type="button" id="download">
          Download drawn routes as GeoJSON
        </button>
      </div>
    </div>
    <div id="map"></div>
    <div id="snap-tool">
      <div id="snap-progress">Route tool loading...</div>
    </div>
    <script type="module">
      // Use the locally built version
      import {
        fetchWithProgress,
        init,
        RouteSnapper,
      } from "./route-snapper/pkg/lib.js";

      // Comment the above and use the published NPM version instead:
      /*import {
        init,
        RouteSnapper,
        fetchWithProgress,
      } from "https://unpkg.com/route-snapper/lib.js";*/

      let map = new maplibregl.Map({
        container: "map",
        style:
          "https://api.maptiler.com/maps/streets/style.json?key=MZEJTanw3WpxRvt7qDfo",
        center: [-0.0961, 51.4922],
        zoom: 13,
        boxZoom: false,
        doubleClickZoom: false,
      });

      let routeSnapper;

      map.on("load", function () {
        map.addSource("boundary", {
          type: "geojson",
          data: {
            type: "Feature",
            geometry: {
              type: "Polygon",
              coordinates: [
                [
                  [-0.113371, 51.474014],
                  [-0.113371, 51.500307],
                  [-0.071072, 51.500307],
                  [-0.071072, 51.474014],
                  [-0.113371, 51.474014],
                ],
              ],
            },
          },
        });
        map.addLayer({
          id: "boundary",
          source: "boundary",
          type: "line",
          paint: {
            "line-color": "black",
            "line-width": 5,
          },
        });

        var completedRoutes = {
          type: "FeatureCollection",
          features: [],
        };
        map.addSource("finished-routes", {
          type: "geojson",
          data: completedRoutes,
        });
        map.addLayer({
          id: "finished-routes",
          source: "finished-routes",
          filter: ["in", "$type", "LineString"],
          type: "line",
          paint: {
            "line-color": "green",
            "line-width": 5,
          },
        });
        map.addLayer({
          id: "finished-areas",
          source: "finished-routes",
          filter: ["in", "$type", "Polygon"],
          type: "fill",
          paint: {
            "fill-color": "green",
            "fill-opacity": 0.2,
          },
        });
        let idCounter = 0;
        let snapTool = document.getElementById("snap-tool");
        snapTool.addEventListener("new-route", (e) => {
          // Assign a unique ID, so we can later delete it
          e.detail.properties.uid = idCounter++;
          completedRoutes.features.push(e.detail);
          map.getSource("finished-routes").setData(completedRoutes);
          if (e.detail.geometry.type == "LineString") {
            document.getElementById(
              "status"
            ).innerText = `Added new route of length ${e.detail.properties.length_meters} meters and name ${e.detail.properties.route_name}`;
          } else {
            document.getElementById("status").innerText = `Added new area`;
          }
        });
        snapTool.addEventListener("activate", (e) => {
          document.getElementById("status").innerText = "Activated";
        });
        snapTool.addEventListener("no-new-route", (e) => {
          document.getElementById("status").innerText =
            "Inactive, no route last attempt";
        });

        document.getElementById("clear").onclick = () => {
          completedRoutes.features = [];
          map.getSource("finished-routes").setData(completedRoutes);
        };

        document.getElementById("start").onclick = () => {
          routeSnapper?.start();
        };
        document.getElementById("stop").onclick = () => {
          routeSnapper?.stop();
        };
        document.getElementById("debugGraph").onclick = () => {
          let gj = routeSnapper?.debugRenderGraph();
          downloadGeneratedFile("route-snapper-graph.geojson", gj);
        };
        document.getElementById("download").onclick = () => {
          downloadGeneratedFile(
            "route-snapper-results.geojson",
            JSON.stringify(completedRoutes)
          );
        };

        map.on("click", (e) => {
          if (!routeSnapper || !routeSnapper.isActive()) {
            let features = map.queryRenderedFeatures(e.point, {
              layers: ["finished-routes", "finished-areas"],
            });
            if (features.length > 0) {
              // If multiple routes overlap, arbitrarily edit one of them
              let editUid = features[0].properties.uid;

              // First remove the route from the completed set, so we don't
              // have duplicates. Be careful with the comparison;
              // queryRenderedFeatures doesn't have back a regular GeoJSON
              // feature. We need to retrieve the full feature for this reason.
              let editFeature;
              completedRoutes.features = completedRoutes.features.filter(
                (f) => {
                  if (f.properties.uid == editUid) {
                    editFeature = f;
                    return false;
                  } else {
                    return true;
                  }
                }
              );
              map.getSource("finished-routes").setData(completedRoutes);

              let roadName = routeSnapper.routeNameForWaypoints(
                editFeature.properties.waypoints
              );
              console.log(`Editing route. Re-calculated name is ${roadName}`);

              routeSnapper.editExisting(editFeature);
            }
          }
        });
      });

      await init();

      const progressUpdateCallback = (progress) => {
        document.getElementById("snap-progress").innerText = `${progress}%`;
      };

      const url = `southwark.bin`;
      try {
        const graphBytes = await fetchWithProgress(url, progressUpdateCallback);
        routeSnapper = new RouteSnapper(
          map,
          graphBytes,
          document.getElementById("snap-tool")
        );
      } catch (err) {
        console.log(`Route tool broke: ${err}`);
        document.getElementById("snap-tool").innerHTML = "Failed to load";
      }

      function downloadGeneratedFile(filename, contents) {
        // Download to a file
        var element = document.createElement("a");
        element.setAttribute(
          "href",
          "data:text/plain;charset=utf-8, " + encodeURIComponent(contents)
        );
        element.setAttribute("download", filename);
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
      }

      document
        .getElementById("fileInput")
        .addEventListener("change", function (event) {
          let file = event.target.files[0];
          let reader = new FileReader();
          reader.onload = function (event) {
            let graphBytes = new Uint8Array(event.target.result);
            routeSnapper?.changeGraph(graphBytes);

            // For convenience, warp somewhere near that graph
            try {
              let gj = JSON.parse(routeSnapper?.debugRenderGraph());
              // Assume nodes (Points) are last.
              map.jumpTo({ center: gj.features[gj.features.length - 1].geometry.coordinates });
            } catch (err) {
              console.log(`Couldn't warp to new graph: ${err}`);
            }
          };
          reader.readAsArrayBuffer(file);
        });
    </script>
  </body>
</html>
